#include "matriz.h"

#define RUNTEST(t,d) { cerr << endl << "Corriendo test " << #t << ": " << #d << endl; t(); cerr << "Terminado test " << #t << " OK!" << endl << endl; }
#define dim 6


void constr() {
    // la copia de una matriz es independiente de otra.
    Matriz m(dim);
    Matriz n(m);
    n.setPos(0,0,2);
    assert( n(0,0) != m(0,0) );
    // el operador asignacion genera matrices independientes
    Matriz o = n;
    o.setPos(0,0,3);
    assert( n(0,0) != o(0,0) );
    // testeando memoria
    Matriz *dinamica = new Matriz(10);
    delete dinamica;
}

void suma(){
	Matriz m(dim);
	Matriz n(dim);
	Matriz res(dim);
	for(int i=0; i<dim; i++) {
		for(int j=0;j<dim;j++) {
			double mij = rand()%11+1;
			double nij = rand()%11+1;
			m.setPos(i,j ,mij);
			n.setPos(i,j ,nij);
			res.setPos(i,j,mij+nij);
		}
	}
	Matriz k = m+n;
	assert(res == k);
}


void resta(){
	Matriz m(dim);
	Matriz n(dim);
	Matriz res(dim);
	for(int i=0;i<dim;i++) {
		for(int j=0;j<dim;j++) {
			double mij = rand()%11+1;
			double nij = rand()%11+1;
			m.setPos(i, j, mij);
			n.setPos(i, j, nij);
			res.setPos(i, j, mij - nij);
		}
	}
	Matriz k = m-n;
	assert( res == k);
}

void times(){
	Matriz m(dim);
	Matriz res(dim);
	double num= rand()%7+1;
	for(int i=0;i<dim;i++){
		for(int j=0;j<dim;j++){
			double mij = rand()%11+1;
			m.setPos(i,j ,mij);
			res.setPos(i, j, num*mij);
		}
	}
	Matriz k = num*m;
	assert(res == k);
}

void times2(){
	Matriz m(dim);
	Matriz n(dim);
	Matriz res(dim);
	for(int i=0;i<dim;i++) {
		for(int j=0;j<dim;j++) {
			m.setPos(i,j ,rand()%11+1);
			n.setPos(i,j ,rand()%11+1);
		}
	}
	for(unsigned int i = 0; i < m.size(); i++){
		for(unsigned int j = 0; j < n.size(); j++){
			double temp = 0;
			for(unsigned int k = 0; k < n.size(); k++){
				temp += m(i,k) * n(k,j);
			}
			res.setPos(i, j, temp);
		}
	}
}

void resolution() {
	Matriz m(dim);
	for(int i=0;i<dim;i++) {
		for(int j=0;j<dim;j++) {
			m.setPos(i,j ,rand()%(23+j)+1);
		}
	}
	double a[dim];
	for(int x = 0; x < dim; x++){
		a[x] = rand()%17;
	}
	double b[dim];
	assert(m.resolver(a,b));
	m.setIdentidad();
	for(int x = 0; x < dim; x++){
		a[x] = 0;
	}
	assert(m.resolver(a,b));
}

void autovectores() {
    Matriz m(dim);
	for(int i=0;i<dim;i++) {
		for(int j=0;j<=i;j++) {
			if(j==i) {
				m.setPos(i,j ,rand()%(23+j)+1);
			} else {
				int val = rand()%(23+j)+1;
				m.setPos(i,j ,val);
				m.setPos(j,i ,val);
			}			
		}
	}
	double n[dim];
	m.autocalcular(n);
	// TODO faltan un par de asserts
}

void norma2(){
    
    double vector[dim];
    for(int i = 0; i < dim; i++){
        vector[i] = 1;
    }
    double norma = Matriz::norma2(vector, dim);
    assert(norma == sqrt(dim));
}

void tc() {
	double e[dim];
	Matriz m(dim);
	for(int i=0;i<dim;i++) {
		for(int j=0;j<=i;j++) {
			if(j==i) {
				m.setPos(i,j ,rand()%(23+j)+1);
			} else {
				int val = rand()%(23+j)+1;
				m.setPos(i,j ,val);
				m.setPos(j,i ,val);
			}			
		}
		e[i] = rand()%11;
	}
    double res[dim];
    int cant = rand()%dim+1;
    m.transformacionCaracteristica(e,res,cant);
    for(int i=0;i<cant;i++) {
        double val=0;
        for(int j=0;j<dim;j++) {
            val += (m(j,i)*e[j]);
        }
        assert(res[i] == val);
    }
}

void inversa() {
    Matriz m(3);
    m.setPos(0,0,1);
    m.setPos(0,1,2);
    m.setPos(0,2,3);
    m.setPos(1,0,2);
    m.setPos(1,1,3);
    m.setPos(1,2,4);
    m.setPos(2,0,3);
    m.setPos(2,1,4);
    m.setPos(2,2,0);

    cout << m << endl;
    m.inversa();
    cout << m << endl;
}

int main(){
    srand(time(NULL));
    RUNTEST(constr, Probando Constructores y asignacion);
    RUNTEST(suma, Probando la suma);
    RUNTEST(resta, Probando la resta);
    RUNTEST(times, Probando multiplicacion escalar);
    RUNTEST(times2, Probando multiplicacion con matriz);
    RUNTEST(resolution, Probando resolver ecuaciones);
    RUNTEST(autovectores, Probando Calculo de autovectores y autovalores);
    RUNTEST(norma2, Probando la norma 2);
    RUNTEST(tc, Pruebando la trasnformacion caracteristica);
    RUNTEST(inversa, Prueba de inversa);
    return 0;
}
